package org.goodsl.mdd.tools;

import groovy.lang.GroovyClassLoader;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.PosixParser;

//import groovyjarjarcommonscli.Options;
//import groovyjarjarcommonscli.CommandLine;
//import groovyjarjarcommonscli.PosixParser;
//import groovyjarjarcommonscli.HelpFormatter;

import groovy.lang.GroovySystem;
import org.codehaus.groovy.control.CompilationUnit;
import org.codehaus.groovy.control.CompilerConfiguration;
import org.codehaus.groovy.tools.ErrorReporter;
import org.codehaus.groovy.tools.FileSystemCompiler;
import org.codehaus.groovy.tools.GroovyClass;
import org.codehaus.groovy.tools.javac.JavaAwareCompilationUnit;
import org.goodsl.mdd.Box;
import org.goodsl.mdd.BoxBuilder;

import java.util.ArrayList;

/**
 * Created with IntelliJ IDEA.
 * User: Simon Xiao
 * Date: 12-11-6
 * Time: 下午2:03
 * To change this template use File | Settings | File Templates.
 */
public class Compiler {

    /**
     * Primary entry point for compiling from the command line
     * (using the mdc script).
     *
     * If calling inside a process and you don't want the JVM to exit on an
     * error call commandLineCompile(String[]), which this method simply wraps
     *
     * @param args command line arguments
     */
    public static void main(String[] args) {
        commandLineCompileWithErrorHandling(args, true);
    }
    private static boolean displayStackTraceOnError = false;

    /**
     * Primary entry point for compiling from the command line
     * (using the mdc script).
     *
     * If calling inside a process and you don't want the JVM to exit on an
     * error call commandLineCompile(String[]), which this method simply wraps
     *
     * @param   args command line arguments
     * @param   lookupUnnamedFiles do a lookup for .groovy files not part of
     *          the given list of files to compile
     */
    public static void commandLineCompileWithErrorHandling(String[] args, boolean lookupUnnamedFiles) {
        try {
            CompilationUnit unit = commandLineCompile(args, lookupUnnamedFiles);
            if(unit!=null){
                System.out.println("Compile Over. Get Total " + unit.getClasses().size() + "classes.");
                System.out.println("Start validate metadata info......");
                validateMddClass(unit);

            }
        } catch( Throwable e ) {
            new ErrorReporter( e, displayStackTraceOnError).write( System.err );
            System.exit(1);
        }
    }

    public static void validateMddClass(CompilationUnit unit){
        GroovyClassLoader loader = unit.getClassLoader();
        ArrayList<Class<?>> classes = new ArrayList<Class<?>>();
        for ( Object obj :unit.getClasses()){
            GroovyClass cb = (GroovyClass)obj;
            Class<?> cz = loader.defineClass(cb.getName(),cb.getBytes());
            classes.add(cz);
        }

        Thread.currentThread().setContextClassLoader(loader);

        for (Class<?> cz : classes){
            if(Box.class.isAssignableFrom(cz)){
                System.out.print(cz.getName() + " -------- ");
                try{
                    BoxBuilder.makeBox(cz);
                    System.out.println("OK");
                }catch (Exception e){
                    System.out.println("ERROR!!!  Detail Info:");
                    e.printStackTrace(System.out);
                }
            }
        }


    }

    /**
      * Same as main(args) except that exceptions are thrown out instead of causing
      * the VM to exit and the lookup for .groovy files can be controlled
      */
     public static CompilationUnit commandLineCompile(String[] args, boolean lookupUnnamedFiles) throws Exception {
    	 Options options = FileSystemCompiler.createCompilationOptions();

         PosixParser cliParser = new PosixParser();

         CommandLine cli;
         cli = cliParser.parse(options, args);

         if (cli.hasOption('h')) {
             displayHelp(options);
             return null;
         }

         if (cli.hasOption('v')) {
             displayVersion();
             return null;
         }

         displayStackTraceOnError = cli.hasOption('e');

         CompilerConfiguration configuration = FileSystemCompiler.generateCompilerConfigurationFromOptions(cli);

         //
         // Load the file name list
         String[] filenames = FileSystemCompiler.generateFileNamesFromOptions(cli);
         boolean fileNameErrors = filenames == null;
         if (!fileNameErrors && (filenames.length == 0)) {
             displayHelp(options);
             return null;
         }

         fileNameErrors = fileNameErrors && !FileSystemCompiler.validateFiles(filenames);

         if (!fileNameErrors) {
             CompilationUnit unit;
             if (configuration.getJointCompilationOptions() != null) {
                 unit = new JavaAwareCompilationUnit(configuration);
             } else {
                 unit = new CompilationUnit(configuration);
             }
             FileSystemCompiler.doCompilation(configuration, unit, filenames, lookupUnnamedFiles);
             return unit;
         }
         return null;
     }
    public static void displayHelp(final Options options) {
        final HelpFormatter formatter = new HelpFormatter();
        formatter.printHelp(80, "mdc [options] <source-files>", "options:", options, "");
    }
    public static void displayVersion() {
        System.err.println("MDD compiler version " + " 0.1");
        String version = GroovySystem.getVersion();
        System.err.println("Groovy compiler version " + version);
        System.err.println("Copyright 2003-2011 The Codehaus. http://groovy.codehaus.org/");
        System.err.println("");
    }


}
